LIFF MockでStorybookにLIFFアプリコンポーネントを作成する

LIFF MockでStorybookにLIFFアプリコンポーネントを作成する

Clock Icon2024.08.13

はじめに

アノテーション株式会社 LINE/DevOpsチームの草竹です!

この記事では、LIFFアプリ(LINEミニアプリ)のUIコンポーネントをStorybookで管理してみた流れを紹介します。

外部と通信するコンポーネントをStorybookで管理する際に必要になってくるのがリクエストのモック化です。
MSWを用いることが多いのではないでしょうか。

今回は、LIFF APIをモック化する手段として公式プラグインのLIFF Mockを使ってみました。

この記事で紹介する内容

  • LIFF Mockの使い方
  • StorybookでLIFF Mockを扱う方法

概要

  • LIFF Mockとは
  • LIFF Mockのセットアップ
  • Storybookとの統合
  • 実際の使用例
  • まとめ

動作環境

項目
@line/liff 2.24.0
@line/liff-mock 1.0.3
storybook 8.2.7
react 18.3.1
vite 5.3.5
typescript 5.5.4

LIFF Mockとは

LINE Developers より引用。

LIFF Mockは、LIFFアプリのテストを簡単にするためのLIFFプラグインです。LIFF Mockを使うと、LIFF SDKにモックモードを追加できます。モックモードでは、LIFFアプリがLIFFサーバーから独立し、LIFF APIがモックデータを返すため、単体テストや負荷テストをより簡単に行うことができます。[1]

LIFF Mockは公式LIFFプラグインの一つ[2]です。LIFFアプリの初期化 liff.init() 時に {mock: true} を付与するだけでかんたんに始めることができます。

LIFF Mockのセットアップ

インストール手順はLIFF MockのGitHubでも紹介されていますので、あわせてご確認ください。

https://github.com/line/liff-mock?tab=readme-ov-file#npm

パッケージをインストールします。

npm i @line/liff @line/liff-mock

line/liff-mock のサンプルコードを参考に、 LIFF の型を拡張します。
liff.init() のオプションに mock を追加したり、liff.$mock を使えるようにTypeScriptに認識させるため必要です。

src/liff.d.ts
import { ExtendedInit, LiffMockApi } from "@line/liff-mock";

declare module "@line/liff" {
  interface Liff {
    init: ExtendedInit;
    $mock: LiffMockApi;
  }
}

LIFFアプリの初期化関数をモジュール化しておきます。

src/lib/liff-init.mock.ts
// LIFF Mock
import { liff } from "@line/liff";
import LiffMockPlugin from "@line/liff-mock";

export const liffInit = async () => {
  liff.use(new LiffMockPlugin());
  await liff
    .init({ liffId: import.meta.env.VITE_LIFF_ID, mock: true })
  // liff.login() が呼ばれている必要があるため
  if (!liff.isInClient()) liff.login()
};

これでLIFF APIのモック化ができるようになりました!
モックデータをセットするには、[メソッド, 戻り値]の[key, value]を liff.$mock.set() に渡してあげればOKです。

今回の例ではLINEプロフィールを表示するメソッド liff.getProfile() をモック化してみます。

このように、getProfile に対して、返してほしい値を渡してあげます。

liff.$mock.set({
  getProfile: {
    displayName: 'KUSATAKE Daisuke',
    userId: '123456789',
    pictureUrl,
    statusMessage: 'お昼休みはもくもくモッキング',
  }
})

Storybookとの統合

StorybookにLIFF Mockを統合するためにやるべきことが2つあります。

  1. liff.init() でLIFFアプリの初期化
  2. liff.$mock.set() でモックデータのセット

私は次のように行いました。

LIFF API Storybook関連ファイル 実行タイミング
liff.init() .storybook/preview.ts -
liff.$mock.set() .src/**/*.stories.ts Story.beforeEach

順を追って説明します。

1. liff.init() でLIFFアプリの初期化

liff.init() での初期化は、プロダクションコードと同様に、他のLIFF APIが実行されるより前に行っておく必要があります。
通常、src/main.tsx 等のエントリーポイントで liff.init() の実行完了を待ってからDOMレンダリングするなどするでしょう。

Storybookでは各ストーリー *.stories.ts のエントリーポイントは .storybook/preview.ts です。ここで初期化します。[4]

.storybook/preview.ts
import type { Preview } from "@storybook/react";
import { liffInit } from "../src/lib/liff-init.mock.ts";

import "src/index.css";

await liffInit()

const preview: Preview = {};

export default preview;

2. liff.$mock.set() でモックデータのセット

次に、各ストーリーで liff.$mock.set() を実行し、本来LIFFサーバーから得る値を任意のモックデータに改竄します。
Story.beforeEach はStoryが呼び出される前に実行されるため、ここでStoryごとにモックデータをセットします。

src/components/UserProfile/UserProfile.stories.ts
// ログインしていて、ユーザープロフィールが取得できているシナリオ
export const LoggedIn: Story = {
  beforeEach: () => {
    liff.$mock.set({
      getProfile: {
        userId: "U1234567890",
        displayName: "草竹 大輔",
        pictureUrl,
        statusMessage: "お昼休みはもくもくモッキング",
      },
    });
  },
};

// ログインされておらず、ユーザープロフィールが取得できていないシナリオ
export const LoggedOut: Story = {
  beforeEach: () => {
    liff.$mock.set({
      getProfile: {
        isLoggedIn: false,
      }
    });
  },
};

これをliff.getProfile()を内部で実行しているコンポーネントのストーリーとして適用させます。

サンプルコンポーネントとして UserProfile.tsx を作成しました。

Storybookを立ち上げて確認すると、モックデータをセットできていることがわかります!モックデータ通りのプロフィール情報が表示されていますね。

Storybook上で LoggedIn, LoggedOut ストーリーを切り替えている。LoggedInでは画像、ユーザー名、ユーザーステータスが表示されている。LoggedOutでは画像、ユーザー名、ユーザーステータスはスケルタルローダーで灰色に点滅している。

他、任意のコンポーネント・LIFF APIについても同様の手順でモックデータをセットすれば実現可能なはずです。

まとめ

LIFF MockとStorybookを統合する際、2つのポイントに注意しました。

  • LIFF Mockの初期化は .storybook/preview.ts で行う
  • LIFF Mockのモックデータのセットは各ストーリーファイル src/**/*.stories.ts で行う

最後までお読みいただきありがとうございました。
今回作成したサンプルプロジェクトを添付します。参考になれば幸いです。

https://github.com/D-ske104/devio-liff-storybook

アノテーション株式会社について

アノテーション株式会社はクラスメソッドグループのオペレーション専門特化企業です。
サポート・運用・開発保守・情シス・バックオフィスの専門チームが、最新 IT テクノロジー、高い技術力、蓄積されたノウハウをフル活用し、お客様の課題解決を行っています。
当社は様々な職種でメンバーを募集しています。
「オペレーション・エクセレンス」と「らしく働く、らしく生きる」を共に実現するカルチャー・しくみ・働き方にご興味がある方は、アノテーション株式会社 採用サイト をぜひご覧ください。

脚注
  1. LIFFプラグイン | LINE Developers ↩︎

  2. 2024/08/05 現在、他にLIFF Inspectorがあります。 ↩︎

  3. LIFF Mockの実装を参照すると、liff.login() が呼ばれていることが前提となることがわかります。 ↩︎

  4. Story rendering: Docs | Storybook ↩︎

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.